iT邦幫忙

2021 iThome 鐵人賽

DAY 15
0
Software Development

在麥塊的農場裡寫 Lua系列 第 15

Day15 Lua 的全域環境變數 _G 與 _ENV

  • 分享至 

  • xImage
  •  

上一回在研究 rom/programs/monitor.lua 的過程中
看到一些大寫的變數 _G, _ENV
心想,該是來面對它們的時候了!

先說在 Lua 5.1 或之前的版本
當我們宣告一個全域變數的時候,會自動被存入 _G 這個全域的 table

a = 1
b = "2"
function c()
    print(3)
end
print(_G.a)     -- 1  _G["a"] 的語法糖
print(_G.b)     -- 2  _G["b"] 的語法糖
print(_G.c)     -- function: 0x13dc770
_G["c"]()       -- 3

如上述程式碼,存取 _G 裡面的元素時,已經預設是全域,不必再指定 _G
並且可以透過在 _G 存入新的值,來宣告全域變數

a = 1
print(a)        -- 等同 print(_G.a) 或 print(_G["a"])
_G["d"] = true
print(d)        -- true

而事實上,之前我一直在使用的 Lua 內建函式庫
也都會存入 _G 這個大表中,也因此我才可以直接呼叫 table.insert(), io.read(), os.date() 等等

print(io)           -- table: 0x195cff0
print(string)       -- table: 0x1956ac0
print(table)        -- table: 0x19588c0
print(table.insert) -- function: 0x42b750
print(os)           -- table: 0x19598d0
print(os.date)      -- function: 0x4272d0
print(print)        -- function: 0x4215c0 最常用的 print,也是全域函數

限制變數環境 (Lua 5.1)

如果想要讓變數環境單純一點,而不是每次都去更動 _G 大表呢?
Lua 5.1 提供了 setfenv 方法,可以改變函數的環境

x = 1
myEnv = {}
setfenv(1, myEnv)
print(x)            -- 這邊會出錯,因為全新的環境 myEnv 還沒有任何變數或方法,就連 print() 都沒有 !

可以用繼承來解決,所有原本 _G 的變數與方法都會繼承

x = 1
myEnv = {}
setmetatable(myEnv, { __index = _G })
setfenv(1, myEnv)
print(x) 

限制變數環境 (Lua 5.2)

Lua 5.2 開始,加入了新的 _ENV 環境
a = 1 相當於 _ENV['a'] = 1
但是 _G 還是可以使用,只是 _ENV["_G"] 指向了 _ENV
也就是 _ENV["_G"] = _ENV,這是為了相容 Lua 5.1 或更舊的程式碼

a = 1
b = 2
print(_ENV.a)
print(_G.b)     -- 相當於 print(_ENV["_G"].b)

此外 setfenv 函數已經廢棄,要在 Lua 5.2 自訂變數環境
則是需要自行宣告新的 _ENV 如下

a = 1
function myfunc()
    local _ENV = { print = print, myvar1 = 2 }
    myvar2 = false
    print(myvar1)       -- 2
    print(_ENV.myvar2)  -- false
    print(_ENV.a)       -- nil  已經是新的環境變數,所以看不到外面的變數 a
end

myfunc()
print(_ENV.a)           -- 1
print(_ENV.myvar1)      -- nil  看不到在函數內自定義的環境變數

對環境變數的實驗與學習先到這裡
覺得已經愈來愈清楚 Lua 的整個環境與架構設計
下次來研究 Lua 的 coroutine 函式庫


上一篇
Day14 用 100 吋超大螢幕寫 Code 的感覺 - 用 metatable 改變預設行為
下一篇
Day16 中斷 Lua 的執行 - coroutine
系列文
在麥塊的農場裡寫 Lua30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言